Lambda(Node.js)でRubyスクリプトを実行する
モバイルアプリサービス部の五十嵐です。
AWS Compute Blogにて、Lmabda(Node.js)でRuby, PHP, Goで書かれたスクリプトを実行する方法が紹介されました。
今回はこの記事で紹介されている中から、Rubyスクリプトの実行を試してみました。また、記事にはありませんがRubygemsをインストールして使う方法も確認しました。
手順
Rubyのスクリプトを実行するLambdaを作成する手順は以下のとおりです。
- AMIからAmazonLinuxのインスタンスを起動し、インスタンス内でLambdaの実行環境を作る
- Lambdaの実行環境と実行するスクリプトをパッケージにしてデプロイする
準備
AWS ConsoleよりEC2インスタンスを起動します。
- Amazon Linux AMI を選択します。
-
インスタンスタイプを選択します。ここでは記事の通り t2.large を選択します。
-
作成し終えたら任意のキーペアを設定します。
インスタンスが起動したら、グローバルIPアドレス(EIP)を確認し、SSHログインします。
$ chmod 400 private.pem $ ssh -i private.pem ec2-user@[グローバルIPアドレス]
環境構築
SSHログインしたら、Rubyの実行環境をインスタンス内で構築します。
$ sudo yum update -y (省略) $ wget http://d6r77u77i8pq3.cloudfront.net/releases/traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz . (省略) $ mkdir LambdaRuby $ tar -xvf traveling-ruby-20150715-2.2.2-linux-x86_64.tar.gz -C LambdaRuby
Lambda in Rubyの作成
ここからはLambdaのパッケージを作成します。今回はserverless frameworkを使用します。
serverless frameworkをインストールしていない場合はインストールします。
$ npm install -g serverless
serverless frameworkのプロジェクトを作成します。
$ sls create -t aws-nodejs -p LambdaRuby Serverless: Generating boilerplate... Serverless: Generating boilerplate in "/Users/igarashi.ryosuke/temp/serverless/LambdaRuby" _______ __ | _ .-----.----.--.--.-----.----| .-----.-----.-----. | |___| -__| _| | | -__| _| | -__|__ --|__ --| |____ |_____|__| \___/|_____|__| |__|_____|_____|_____| | | | The Serverless Application Framework | | serverless.com, v1.3.0 -------' Serverless: Successfully generated boilerplate for template: "aws-nodejs" $ cd LambdaRuby $ ll total 16 -rw-r--r-- 1 igarashi.ryosuke staff 466B 12 12 14:20 handler.js -rw-r--r-- 1 igarashi.ryosuke staff 2.2K 12 12 14:20 serverless.yml
handler.jsを以下のように書き替えます。
'use strict'; const exec = require('child_process').exec; module.exports.hello = (event, context, callback) => { const child = exec('./lambdaRuby.rb ' + ''' + JSON.stringify(event) + ''', (result) => { // Resolve with result of process context.done(result); }); // Log process stdout and stderr child.stdout.on('data', console.log); child.stderr.on('data', console.error); };
続いて実行したいRubyスクリプトを作成します。今回は記事のサンプルにあるlambdaRuby.rbを使います。
#!./bin/ruby require 'json' # You can use this to check your Ruby version from within puts(RUBY_VERSION) if ARGV.length > 0 puts JSON.parse( ARGV[0] ).length else puts "0" end
実行権限も必要なので設定します。
$ chmod +x lambdaRuby.rb
ローカル環境で実行できることを確認します。
$ ruby lambdaRuby.rb '{ "we" : "love", "using" : "Lambda" }' 2
テスト用のパラメータファイル event.json を作成します。
{"key3": "value3","key2": "value2","key1": "value1"}
EC2上で作成した実行環境をダウンロードします。
$ scp -r -i ~/.ssh/private.pem ec2-user@[グローバルIPアドレス]:~/LambdaRuby/bin . $ scp -r -i ~/.ssh/private.pem ec2-user@[グローバルIPアドレス]:~/LambdaRuby/bin.real . $ scp -r -i ~/.ssh/private.pem ec2-user@[グローバルIPアドレス]:~/LambdaRuby/info . $ scp -r -i ~/.ssh/private.pem ec2-user@[グローバルIPアドレス]:~/LambdaRuby/lib . $ ll total 32 drwxrwxr-x 7 igarashi.ryosuke staff 238B 12 12 15:05 bin drwxr-xr-x 18 igarashi.ryosuke staff 612B 12 12 15:05 bin.real -rw-r--r-- 1 igarashi.ryosuke staff 53B 12 12 15:21 event.json -rw-r--r-- 1 igarashi.ryosuke staff 423B 12 12 15:25 handler.js drwxrwxr-x 6 igarashi.ryosuke staff 204B 12 12 15:05 info -rwxr-xr-x 1 igarashi.ryosuke staff 187B 12 12 14:25 lambdaRuby.rb drwxr-xr-x 9 igarashi.ryosuke staff 306B 12 12 15:05 lib -rw-r--r-- 1 igarashi.ryosuke staff 2.2K 12 12 14:20 serverless.yml
デプロイします。
$ sls deploy Serverless: Creating Stack... Serverless: Checking Stack create progress... ..... Serverless: Stack create finished... Serverless: Packaging service... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading service .zip file to S3 (7.22 MB)... Serverless: Updating Stack... Serverless: Checking Stack update progress... ............... Serverless: Stack update finished... Service Information service: LambdaRuby stage: dev region: us-east-1 api keys: None endpoints: None functions: LambdaRuby-dev-hello: arn:aws:lambda:us-east-1:XXXXXXXXXXXX:function:LambdaRuby-dev-hello
テストします。
$ sls invoke -f hello -p event.json { "errorMessage": "missing ) after argument list", "errorType": "SyntaxError", "stackTrace": [ "Module.load (module.js:343:32)", "Function.Module._load (module.js:300:12)", "Module.require (module.js:353:17)", "require (internal/module.js:12:17)" ] }
handler.js からRubyスクリプトにパラメータを渡す箇所のエスケープが正しくなかったので修正します。
- const child = exec('./lambdaRuby.rb ' + ''' + JSON.stringify(event) + ''', (result) => { + const child = exec('./lambdaRuby.rb ' + "'" + JSON.stringify(event) + "'", (result) => {
もう一度デプロイしてテストします。
$ sls deploy $ sls invoke -f hello -p event.json null
ログを確認します。
$ sls logs -f hello START RequestId: a50c91de-c036-11e6-a481-8f341729cc0f Version: $LATEST 2016-12-12 15:46:02.046 (+09:00) a50c91de-c036-11e6-a481-8f341729cc0f 3 END RequestId: a50c91de-c036-11e6-a481-8f341729cc0f REPORT RequestId: a50c91de-c036-11e6-a481-8f341729cc0f Duration: 288.31 ms Billed Duration: 300 ms Memory Size: 1024 MB Max Memory Used: 23 MB
正常に動作することが確認できました。
Rubygemsを使う
実用的なスクリプトを作るにはRubygemsも使える必要があるので、インストールしたgemも使えるかどうか試してみました。
先程のインスタンスに、SSHログインして、gemをインストールします。
$ ./LambdaRuby/bin/gem install faker --no-ri --no-rdoc Fetching: i18n-0.7.0.gem (100%) Successfully installed i18n-0.7.0 Fetching: faker-1.6.6.gem (100%) Successfully installed faker-1.6.6 2 gems installed $ ls -l LambdaRuby/lib/ruby/gems/2.2.0/gems/ 合計 12 drwxrwxr-x 4 ec2-user ec2-user 4096 7月 14 2015 bundler-1.9.9 drwxrwxr-x 3 ec2-user ec2-user 4096 12月 13 07:27 faker-1.6.6 drwxrwxr-x 5 ec2-user ec2-user 4096 12月 13 07:27 i18n-0.7.0
ローカル環境に戻り、gemをインストールしたディレクトリごとファイルをダウンロードします。
$ scp -r -i ~/.ssh/private.pem ec2-user@[グローバルIPアドレス]:~/LambdaRuby/lib . $ ls -l lib/ruby/gems/2.2.0/gems/ total 0 drwxrwxr-x 12 igarashi.ryosuke staff 408 12 12 16:05 babymetal-0.1.6 drwxrwxr-x 5 igarashi.ryosuke staff 170 12 12 15:05 bundler-1.9.9
Rubyスクリプトを修正します。
require 'faker' puts Faker::Name.name
デプロイして、実行します。
$ sls deploy $ sls invoke -f hello -p event.json null
ログを確認します。
$ sls logs -f hello START RequestId: 7de1992e-c106-11e6-b626-712e694e52b4 Version: $LATEST 2016-12-13 16:33:52.944 (+09:00) 7de1992e-c106-11e6-b626-712e694e52b4 Isabelle Ortiz END RequestId: 7de1992e-c106-11e6-b626-712e694e52b4 REPORT RequestId: 7de1992e-c106-11e6-b626-712e694e52b4 Duration: 1296.70 ms Billed Duration: 1300 ms Memory Size: 1024 MB Max Memory Used: 31 MB
最初のサンプルと同様に、ログに結果が出力されていることが分かります。
まとめ
今回はRubyを試しましたが、他の言語も同様に言語の実行環境ごとパッケージにしてLambdaのコンテナ内で実行するということをやっているようです。既存のスクリプトをLambdaに移行したい場合の一つの選択肢として覚えておくと良いかもしれません。